package com.luisliuyi.demo.binderlib.core;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

import com.luisliuyi.demo.binderlib.BinderInterface;
import com.luisliuyi.demo.binderlib.ClassId;
import com.luisliuyi.demo.binderlib.ServiceManager;
import com.luisliuyi.demo.binderlib.bean.RequestBean;
import com.luisliuyi.demo.binderlib.bean.RequestParamter;
import com.luisliuyi.demo.binderlib.cache.CacheCenter;
import com.google.gson.Gson;
import android.content.ServiceConnection;
import android.text.TextUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class BinderIPC {
    private CacheCenter cacheCenter = CacheCenter.getInstance();
    private static final BinderIPC ourInstance = new BinderIPC();
    BinderInterface binderInterface;
    private static final Gson GSON = new Gson();
    private Context sContext;

    public static BinderIPC getDefault() {
        return ourInstance;
    }

    public void init(Context context) {
        sContext = context.getApplicationContext();
    }

    public void register(Class<?> clazz) {
        cacheCenter.register(clazz);
    }

    public <T> T getInstance(Class<T> clazz, Object... parameters) {
        sendRequest(clazz, null, parameters, ServiceManager.TYPE_GET);
        return getProxy(clazz);
    }

    private <T> T getProxy(Class<T> clazz) {
        ClassLoader classLoader = sContext.getClassLoader();
        return (T) Proxy.newProxyInstance(classLoader, new Class[]{clazz}, new BinderProxy(clazz));
    }

    public <T> String sendRequest(Class<T> clazz, Method method, Object[] parameters, int type) {
        String className = clazz.getAnnotation(ClassId.class).value();
        String methodName = method == null ? "getInstance" : method.getName();
        RequestParamter[] requestParamters = null;
        if (parameters != null && parameters.length >0) {
            requestParamters = new RequestParamter[parameters.length];
            for (int i = 0; i < parameters.length; i++) {
                Object parameter = parameters[i];
                String parameterClassName = parameter.getClass().getName();
                String parameterValue = GSON.toJson(parameter);
                RequestParamter requestParamter = new RequestParamter(parameterClassName, parameterValue);
                requestParamters[i] = requestParamter;
            }
        }

        RequestBean requestBean = new RequestBean(type, className, methodName, requestParamters);
        String request = GSON.toJson(requestBean);
        String responce = null;
        try {
            responce= binderInterface.reuqest(request);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return responce;
    }

    public void open(Context context) {
        open(context, null);
    }

    public void open(Context context, String packageName) {
        init(context);
        bind(context.getApplicationContext(), packageName, ServiceManager.class);
    }

    private void bind(Context context, String packageName, Class<? extends ServiceManager> service) {
        Intent intent = null;
        if (TextUtils.isEmpty(packageName)) {
            intent = new Intent(context, service);
        }else {
            ComponentName component = new ComponentName(packageName, service.getName());
            intent = new Intent();
            intent.setComponent(component);
            intent.setAction(service.getName());
        }
        ServiceConnection serviceConnection = new IPCServiceConnection();
        context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    private class IPCServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            binderInterface = BinderInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
}
